PROJECT = "ModbusRTU从站测试"
VERSION = "1.0.0"

local sys = require("sys")
local ModbusRTU_Slave = require("ModbusRTU_Slave") -- 引用ModbusRTU主站库

if wdt then
    -- 添加硬狗防止程序卡死，在支持的设备上启用这个功能
    wdt.init(9000) -- 初始化watchdog设置为9s
    sys.timerLoopStart(wdt.feed, 3000) -- 3s喂一次狗
end

-- 创建ModbusRTU从站实例    依次是 串口号 从站地址（其他都是默认值，如果有需要可以更改）
local uart11 = ModbusRTU_Slave:new({
    -- 配置串口
    uartid = 11,
    slave_addr = 0x01,

    -- 分别配置不同数据区的大小
    holding_registers_count = 10, -- 保持寄存器数量
    coils_count = 20 -- 线圈数量（用于测试0x01，0x05.0x0F功能码
})

-- 初始化保存寄存器测试数据
uart11:write_registers(0, 1234) -- 先地址0写入1234
uart11:write_registers(1, 111) -- 先地址1写入111
uart11:write_registers(2, 222) -- 先地址2写入222
uart11:write_registers(3, 333) -- 先地址3写入333
uart11:write_registers(4, 444) -- 先地址4写入444
uart11:write_registers(5, 555) -- 先地址5写入555
uart11:write_registers(6, 666) -- 先地址6写入666
uart11:write_registers(7, 777) -- 先地址7写入777

-- 初始化线圈测试数据（用于测试0x01，0x05.0x0F功能码）
uart11.coils[0] = true -- 线圈0设置为true
uart11.coils[1] = false -- 线圈1设置为false
uart11.coils[2] = true -- 线圈2设置为true
uart11.coils[3] = false -- 线圈3设置为false
uart11.coils[4] = true -- 线圈4设置为true

-- 全局变量用于缓存未完成的 Modbus 帧
local frame_buffer = ""

sys.timerLoopStart(function()

    local data = uart.read(11, 512)

    if #data > 0 then
        log.info("从串口中读取到的数据，长度：", #data, "内容：", data:toHex())
        -- frame_buffer = "" -- 清空缓存

        -- 将新数据追加到缓存中
        frame_buffer = frame_buffer .. data

        -- 检查是否满足最小帧长度
        while #frame_buffer >= 8 do
            local fc = string.byte(frame_buffer, 2)
            local addr = string.byte(frame_buffer, 1)

            log.info("解析帧数据，地址:", addr, "功能码:", fc, "缓冲区长度:", #frame_buffer)

            -- 判断功能码并计算帧长度
            local frame_length = 0
            if fc == 0x01 or fc == 0x02 or fc == 0x03 or fc == 0x04 then
                -- 读线圈/离散输入/寄存器: 起始地址(2)+数量(2)
                frame_length = 8 -- 地址(1) + 功能码(1) + 起始(2) + 数量(2) + CRC(2)
            elseif fc == 0x05 or fc == 0x06 then
                -- 写单个线圈/寄存器: 地址(2)+值(2)
                frame_length = 8
            elseif fc == 0x0F then
                -- 写多个线圈: 起始地址(2)+数量(2)+字节数(1)+数据(n)
                local byte_count = string.byte(frame_buffer, 7)
                frame_length = 7 + byte_count + 2 -- 地址+功能码+起始+数量+字节计数+数据+CRC
            elseif fc == 0x10 then
                -- 写多个寄存器: 从机地址(1)+功能码(1)+起始地址(2)+数量(2)+字节数(1)+数据(n*2)+CRC(2)
                local byte_count = string.byte(frame_buffer, 7)
                frame_length = 9 + byte_count
                log.info("0x10写入保持寄存器的数量：", byte_count, "0x10 帧长度为：", frame_length)
            else
                log.warn("未知功能码", fc)
                frame_buffer = "" -- 清空缓冲区
                break
            end

            log.info("计算得到的帧长度:", frame_length)

            -- 检查是否有完整的帧
            if #frame_buffer >= frame_length then
                local frame = frame_buffer:sub(1, frame_length)
                frame_buffer = frame_buffer:sub(frame_length + 1)
                log.info("当前缓冲区长度:", #frame_buffer, "内容:", frame_buffer:toHex())
                log.info("计算帧长度:", frame_length, "截取后剩余长度:", #frame_buffer - frame_length)

                log.debug("当前缓冲区", frame_buffer:toHex())
                -- 处理帧
                log.info("收到Modbus主站请求", frame:toHex())

                -- 获取响应帧
                local response = uart11:handle_modbus_request(frame)

                if response then
                    -- 直接发送响应帧
                    log.info("发送给Modbus主站响应", response:toHex())
                    uart.write(11, response)
                else
                    log.warn("未生成有效的响应帧")
                end
            else
                log.info("帧不完整，等待更多数据")
                break
            end

        end
    end

end, 10)

sys.run()
